package com.example.demo.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * Redis 分布式锁：利用 RedisTemplate
 * 核心加锁逻辑：
 * <p>
 * Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, "stock", 10, TimeUnit.SECONDS);
 * <p>
 * 原生命令：setnx,加锁设置过期时间
 * <p>
 * 存在问题：A把B的锁释放了
 * <p>
 * 解决办法：
 * 设置标识 versionId，如果锁是自己加的就释放
 * if(versionId.equals(redisTemplate.opsForValue().get(lockKey))){
 * redisTemplate.delete(lockKey);
 * }
 * <p>
 * 模拟场景：
 * Pod1: 8080   url :  http://localhost:8080/stock/sync
 * <p>
 * Pod2: 8081   url :  http://localhost:8081/stock/sync
 * IDEA  配置：  VM-Option: -Dserver.port=8081
 */
@RestController
public class IndexController_RedisTemplate {

    //@Autowired
    // private Redisson redisson;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final DefaultRedisScript<Long> UNLOCK_LUA_SCRIPT;

    static {
        // 类加载时就初始化
        UNLOCK_LUA_SCRIPT = new DefaultRedisScript<>();
        // 加载Lua脚本
        UNLOCK_LUA_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));
        // 返回值类型
        UNLOCK_LUA_SCRIPT.setResultType(Long.class);
    }


    @RequestMapping("/redisLock/reduceStock")
    public String reduceStock() {

        String lockKey = "product_01";  //key
        String versionId = UUID.randomUUID().toString(); //value

        //非原子操作
        //redisTemplate.opsForValue().setIfAbsent(lockKey, versionId); //setnx key value
        //redisTemplate.expire(lockKey, 30, TimeUnit.SECONDS); //expire key seconds


        //原子操作

        Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, versionId, 10, TimeUnit.SECONDS);

        if (!result) {
            return "系统异常";
        }
        String msg = "";
        try {
            int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock"));
            if (stock > 0) {
                int realStock = stock - 1;
                redisTemplate.opsForValue().set("stock", realStock + "");
                msg = "减库存成功，剩余:" + realStock;
                System.out.println(msg);
            } else {
                msg = "减库存失败，库存不足";
                System.out.println(msg);
            }
        } finally {
            //redisTemplate.delete(lockKey);
            //判断如果是自己加的锁，就释放
            /*if (versionId.equals(redisTemplate.opsForValue().get(lockKey))) {
                //TODO 网络抖动，宕机，可能存在锁错误释放额问题
                redisTemplate.delete(lockKey);
            }*/

            System.out.println("锁释放前：" + redisTemplate.opsForValue().get(lockKey));

            // 执行lua脚本释放锁
            redisTemplate.execute(UNLOCK_LUA_SCRIPT, Collections.singletonList(lockKey), versionId);

            System.out.println("锁释放后：" + redisTemplate.opsForValue().get(lockKey));

        }
        return msg;
    }

}
